/**
 * Create by CaoWenjian
 *
 * @copyRight: 2018
 **/
package com.bjboot.caocao.system.shiro;

import com.bjboot.caocao.system.config.ApplicationContextComponent;
import com.bjboot.caocao.system.dao.UserDao;
import com.bjboot.caocao.system.domain.UserDO;
import com.bjboot.caocao.system.service.MenuService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *@Description Realm继承AuthorizingRealm 实现用户认证
 *@Author 操文健
 *@Date 2018-09-06 上午9:43
 *@Version 1.0
 **/
public class UserRealm extends AuthorizingRealm {
    private final Logger logger = LoggerFactory.getLogger(UserRealm.class);
    /**
     * 权限控制（重写doGetAuthorizationInfo）
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("获取用户对菜单的权限集合信息...");
        // 根据容器上下文拿到spring中的对象
        MenuService menuService = ApplicationContextComponent.getBean(MenuService.class);
        // 获取用户Id
        UserDO curUser = ShiroUtils.getUser();
        Long userId = curUser.getUserId();
        // 根据用户Id获取该用户对应的角色和角色对应的所有的权限信息 「不重复的权限信息」
        Set<String> perms = menuService.listPerms(userId);
        // 创建返回的权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(perms);
        logger.info("用户【" + curUser.getName() + "】权限查询成功...");
        logger.debug("该用户对应的权限为：" + perms);
        return info;
    }

    /**
     * 身份【登陆】认证（重写doGetAuthenticationInfo）
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取当前登陆的用户名和密码信息
        String userName = (String) authenticationToken.getPrincipal();
        logger.info("开始对用户【" + userName + "】进行认证...");
        String passWord = new String((char[]) authenticationToken.getCredentials());

        // 根据spring上下文获取当前用户的Mapper接口
        UserDao userDao = ApplicationContextComponent.getBean(UserDao.class);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("username", userName);
        // 根据用户名查询用户信息
        List<UserDO> userDOList = userDao.list(paramMap);

        // 开始对用户信息进行比对
        if (userDOList == null || userDOList.size() == 0 || userDOList.get(0) == null) {
            logger.info("用户账号为【" + userName + "】对用户不存在");
            throw new UnknownAccountException("用户账号不存在");
        }
        // 优化，防止用户不存在的情况下抛出空指针异常的信息
        UserDO userDO = userDOList.get(0);
        if (!passWord.equals(userDO.getPassword())) {
            logger.info("用户【" + userName + "】对应输入对应对密码不正确");
            throw new IncorrectCredentialsException("用户密码不正确");
        }

        // 账号锁定
        if (userDO.getStatus() == 0) {
            logger.info("用户【" + userName + "】账号已被锁定");
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }

        // 认证成功，组装对应的用户认证信息
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDO, passWord, getName());
        return info;
    }
}
